﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Printing;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Common;
using IssueVision.EntityModel;

namespace IssueVision.ViewModel
{
    [Export(ViewModelTypes.BugReportViewModel, typeof(ViewModelBase))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class BugReportViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IIssueVisionModel _issueVisionModel;
        private ReportPrintout _reportPrintOut;
        private int _printedItems;
        #endregion "Private Data Members"

        #region "Constructor"
        [ImportingConstructor]
        public BugReportViewModel(IIssueVisionModel issueVisionModel)
        {
            _issueVisionModel = issueVisionModel;

            // Set up event handling
            _issueVisionModel.GetAllUnresolvedIssuesCompleted += _issueVisionModel_GetAllUnresolvedIssuesCompleted;
            _issueVisionModel.GetActiveBugCountByMonthCompleted += _issueVisionModel_GetActiveBugCountByMonthCompleted;
            _issueVisionModel.GetResolvedBugCountByMonthCompleted += _issueVisionModel_GetResolvedBugCountByMonthCompleted;
            _issueVisionModel.GetActiveBugCountByPriorityCompleted += _issueVisionModel_GetActiveBugCountByPriorityCompleted;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // load all issues
            _issueVisionModel.GetAllUnresolvedIssuesAsync();
            _issueVisionModel.GetActiveBugCountByMonthAsync(6);
            _issueVisionModel.GetResolvedBugCountByMonthAsync(6);
            _issueVisionModel.GetActiveBugCountByPriorityAsync();
        }
        #endregion "Constructor"

        #region "ICleanup interface implementation"
        public override void Cleanup()
        {
            if (_issueVisionModel != null)
            {
                // unregister all events
                _issueVisionModel.GetAllUnresolvedIssuesCompleted -= _issueVisionModel_GetAllUnresolvedIssuesCompleted;
                _issueVisionModel.GetActiveBugCountByMonthCompleted -= _issueVisionModel_GetActiveBugCountByMonthCompleted;
                _issueVisionModel.GetResolvedBugCountByMonthCompleted -= _issueVisionModel_GetResolvedBugCountByMonthCompleted;
                _issueVisionModel.GetActiveBugCountByPriorityCompleted -= _issueVisionModel_GetActiveBugCountByPriorityCompleted;
                _issueVisionModel.PropertyChanged -= _issueVisionModel_PropertyChanged;
                _issueVisionModel = null;
            }
            // set properties back to null
            AllIssues = null;
            ActiveBugCountByMonth = null;
            ResolvedBugCountByMonth = null;
            ActiveBugCountByPriority = null;
            // unregister any messages for this ViewModel
            base.Cleanup();
        }
        #endregion "ICleanup interface implementation"

        #region "Public Properties"

        private IEnumerable<Issue> _allIssues;

        public IEnumerable<Issue> AllIssues
        {
            get { return _allIssues; }
            private set
            {
                if (!ReferenceEquals(_allIssues, value))
                {
                    _allIssues = value;
                    RaisePropertyChanged("AllIssues");
                }
            }
        }

        private IEnumerable<BugCountByMonth> _activeBugCountByMonth;

        public IEnumerable<BugCountByMonth> ActiveBugCountByMonth
        {
            get { return _activeBugCountByMonth; }
            private set
            {
                if (!ReferenceEquals(_activeBugCountByMonth, value))
                {
                    _activeBugCountByMonth = value;
                    RaisePropertyChanged("ActiveBugCountByMonth");
                }
            }
        }

        private IEnumerable<BugCountByMonth> _resolvedBugCountByMonth;

        public IEnumerable<BugCountByMonth> ResolvedBugCountByMonth
        {
            get { return _resolvedBugCountByMonth; }
            private set
            {
                if (!ReferenceEquals(_resolvedBugCountByMonth, value))
                {
                    _resolvedBugCountByMonth = value;
                    RaisePropertyChanged("ResolvedBugCountByMonth");
                }
            }
        }

        private IEnumerable<BugCountByPriority> _activeBugCountByPriority;

        public IEnumerable<BugCountByPriority> ActiveBugCountByPriority
        {
            get { return _activeBugCountByPriority; }
            private set
            {
                if (!ReferenceEquals(_activeBugCountByPriority, value))
                {
                    _activeBugCountByPriority = value;
                    RaisePropertyChanged("ActiveBugCountByPriority");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand _printReportCommand;

        public RelayCommand PrintReportCommand
        {
            get
            {
                if (_printReportCommand == null)
                {
                    _printReportCommand = new RelayCommand(
                        () => OnPrintReportCommand(),
                        () => (_issueVisionModel != null) && !(_issueVisionModel.IsBusy));
                }
                return _printReportCommand;
            }
        }

        private void OnPrintReportCommand()
        {
            try
            {
                PrintDocument printDocument = new PrintDocument();
                printDocument.BeginPrint += printDocument_BeginPrint;
                printDocument.PrintPage += printDocument_PrintPage;
                printDocument.EndPrint += printDocument_EndPrint;
                printDocument.Print("IssueVision Bug Report");
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        /// <summary>
        /// Event handler for GetAllUnresolvedIssuesCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetAllUnresolvedIssuesCompleted(object sender, ResultsArgs<Issue> e)
        {
            if (!e.HasError)
            {
                AllIssues = e.Results
                    .OrderBy(g => g.Priority)
                    .ThenBy(g => g.Severity);
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for GetActiveBugCountByMonthCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetActiveBugCountByMonthCompleted(object sender, ResultsArgs<string> e)
        {
            if (!e.HasError)
            {
                List<BugCountByMonth> bugCountList = new List<BugCountByMonth>();
                foreach (string bugCount in e.Results)
                {
                    bugCountList.Add(
                        new BugCountByMonth
                        {
                            Month = bugCount.Substring(0, 3) + bugCount.Substring(5, 2),
                            Count = Convert.ToInt32(bugCount.Substring(8))
                        });
                }
                ActiveBugCountByMonth = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for GetResolvedBugCountByMonthCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetResolvedBugCountByMonthCompleted(object sender, ResultsArgs<string> e)
        {
            if (!e.HasError)
            {
                List<BugCountByMonth> bugCountList = new List<BugCountByMonth>();
                foreach (string bugCount in e.Results)
                {
                    bugCountList.Add(
                        new BugCountByMonth
                        {
                            Month = bugCount.Substring(0, 3) + bugCount.Substring(5, 2),
                            Count = Convert.ToInt32(bugCount.Substring(8))
                        });
                }
                ResolvedBugCountByMonth = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for GetActiveBugCountByPriorityCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetActiveBugCountByPriorityCompleted(object sender, ResultsArgs<string> e)
        {
            if (!e.HasError)
            {
                List<BugCountByPriority> bugCountList = new List<BugCountByPriority>();
                foreach (string bugCount in e.Results)
                {
                    bugCountList.Add(
                        new BugCountByPriority
                        {
                            Priority = Convert.ToByte(bugCount.Substring(0, bugCount.IndexOf('/'))),
                            Count = Convert.ToInt32(bugCount.Substring(bugCount.IndexOf('/') + 1))
                        });
                }
                ActiveBugCountByPriority = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("IsBusy"))
            {
                PrintReportCommand.RaiseCanExecuteChanged();
            }
        }

        /// <summary>
        /// Event handler for BeginPrint
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void printDocument_BeginPrint(object sender, BeginPrintEventArgs e)
        {
            // get the charts currently in display as a WriteableBitmap
            WriteableBitmap writeableBitmap = null;
            var message = new NotificationMessageAction<WriteableBitmap>("Get Charts", s => writeableBitmap = s);
            AppMessages.GetChartsMessage.Send(message);

            _reportPrintOut = new ReportPrintout(writeableBitmap);
            _printedItems = 0;
        }

        /// <summary>
        /// Event handler for PrintPage
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            if (_reportPrintOut != null)
            {
                e.PageVisual = _reportPrintOut;
                _reportPrintOut.Paginate(AllIssues, _printedItems, _printedItems == 0, e.PrintableArea);
                _printedItems += _reportPrintOut.NumItemsShown;
                e.HasMorePages = _printedItems < AllIssues.Count();
            }
            else
                e.HasMorePages = false;
        }

        /// <summary>
        /// Event handler for EndPrint
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void printDocument_EndPrint(object sender, EndPrintEventArgs e)
        {
            _reportPrintOut = null;
        }

        #endregion "Private Methods"
    }
}